local function speed_attach(inst, target)
    if target.components.locomotor ~= nil then
        target.components.locomotor:SetExternalSpeedMultiplier(target, inst.prefab, TUNING.NUTSBUFF_SPEED1_MULT) -- 0.2
    end
end

local function speed_detach(inst, target)
    if target.components.locomotor ~= nil then
        target.components.locomotor:RemoveExternalSpeedMultiplier(target, inst.prefab)
    end
end

local function speed2_attach(inst, target)
    if target.components.locomotor ~= nil then
        target.components.locomotor:SetExternalSpeedMultiplier(target, inst.prefab, TUNING.NUTSBUFF_SPEED2_MULT) -- 0.5
    end
end

local function speed2_detach(inst, target)
    if target.components.locomotor ~= nil then
        target.components.locomotor:RemoveExternalSpeedMultiplier(target, inst.prefab)
    end
end

local function speed3_attach(inst, target)
    if target.components.locomotor ~= nil then
        target.components.locomotor:SetExternalSpeedMultiplier(target, inst.prefab, TUNING.NUTSBUFF_SPEED3_MULT) -- 0.1
    end
end

local function speed3_detach(inst, target)
    if target.components.locomotor ~= nil then
        target.components.locomotor:RemoveExternalSpeedMultiplier(target, inst.prefab)
    end
end


local function work_attach(inst, target)
    if target.components.workmultiplier == nil then
        target:AddComponent("workmultiplier")
    end
    target.components.workmultiplier:AddMultiplier(ACTIONS.CHOP, TUNING.BUFF_WORKEFFECTIVENESS_MODIFIER, inst)
    target.components.workmultiplier:AddMultiplier(ACTIONS.MINE, TUNING.BUFF_WORKEFFECTIVENESS_MODIFIER, inst)
    target.components.workmultiplier:AddMultiplier(ACTIONS.HAMMER, TUNING.BUFF_WORKEFFECTIVENESS_MODIFIER, inst)
end

local function work_detach(inst, target)
    if target.components.workmultiplier ~= nil then
        target.components.workmultiplier:RemoveMultiplier(ACTIONS.CHOP, inst)
        target.components.workmultiplier:RemoveMultiplier(ACTIONS.MINE, inst)
        target.components.workmultiplier:RemoveMultiplier(ACTIONS.HAMMER, inst)
    end
end

local function strength_attach(inst, target)
    if target.components.combat then
        target.components.combat.externaldamagemultipliers:SetModifier(inst, TUNING.NUTSBUFF_STRENGTH_MULT, inst.prefab)
    end
end

local function strength_detach(inst, target)
    if target.components.combat then
        target.components.combat.externaldamagemultipliers:RemoveModifier(inst, inst.prefab)
    end
end

local function banana_attach(inst, target)
    target:AddTag("nutprotect_banana")
end

local function banana_detach(inst, target)
    target:RemoveTag("nutprotect_banana")
end


local function moisture_attach(inst, target)
    if target.components.moistureimmunity == nil then
        target:AddComponent("moistureimmunity")
    end
    target.components.moistureimmunity:AddSource(inst)
end

local function moisture_detach(inst, target)
    if target.components.moistureimmunity ~= nil then
        target.components.moistureimmunity:RemoveSource(inst)
    end
end


local function OnTick(inst, target)
    if target.components.health ~= nil
        and not target.components.health:IsDead()
        and target.components.sanity ~= nil
        and not target:HasTag("playerghost") then
        target.components.sanity:DoDelta(1)
    else
        inst.components.debuff:Stop()
    end
end

local function sanity_attach(inst, target)
    inst.task = inst:DoPeriodicTask(2, OnTick, nil, target)
end

local function sanity_extend(inst, target)
    inst.components.timer:StopTimer("buffover")
    inst.components.timer:StartTimer("buffover", TUNING.NUTSBUFF_SANITY_DURATION)
    -- inst.task:Cancel()
    -- inst.task = inst:DoPeriodicTask(TUNING.SWEETTEA_TICK_RATE, OnTick, nil, target)
end


local function powder_attach(inst, target)
    if target.components.stackable ~= nil then
        target:RemoveComponent("stackable")
    end
    target:AddTag("nuts_coffeed")
    target:AddTag("spicedfood")
    target.inv_image_bg = { atlas = target.replica.inventoryitem:GetAtlas(), image = target.replica.inventoryitem:GetImage() }
end


local function yutu_attach(inst, target)
    target:AddTag("nuts_yutu")
end

local function yutu_detach(inst, target)
    target:RemoveTag("nuts_yutu")
end

local function OnTimerDone(inst, data)
    if data.name == "buffover" then
        inst.components.debuff:Stop()
    end
end

local function MakeBuff(name, onattachedfn, onextendedfn, ondetachedfn, duration, priority, prefabs)
    local ATTACH_BUFF_DATA = {
        buff = "ANNOUNCE_ATTACH_BUFF_" .. string.upper(name),
        priority = priority
    }
    local DETACH_BUFF_DATA = {
        buff = "ANNOUNCE_DETACH_BUFF_" .. string.upper(name),
        priority = priority
    }

    local function OnAttached(inst, target)
        inst.entity:SetParent(target.entity)
        inst.Transform:SetPosition(0, 0, 0) --in case of loading
        inst:ListenForEvent("death", function()
            inst.components.debuff:Stop()
        end, target)

        if priority then
            target:PushEvent("foodbuffattached", ATTACH_BUFF_DATA)
        end
        if onattachedfn ~= nil then
            onattachedfn(inst, target)
        end
    end

    local function OnExtended(inst, target)
        inst.components.timer:StopTimer("buffover")
        inst.components.timer:StartTimer("buffover", duration)

        if priority then
            target:PushEvent("foodbuffattached", ATTACH_BUFF_DATA)
        end
        if onextendedfn ~= nil then
            onextendedfn(inst, target)
        end
    end

    local function OnDetached(inst, target)
        if ondetachedfn ~= nil then
            ondetachedfn(inst, target)
        end

        if priority then
            target:PushEvent("foodbuffdetached", DETACH_BUFF_DATA)
        end
        inst:Remove()
    end

    local function fn()
        local inst = CreateEntity()

        if not TheWorld.ismastersim then
            --Not meant for client!
            inst:DoTaskInTime(0, inst.Remove)
            return inst
        end

        inst.entity:AddTransform()

        --[[Non-networked entity]]
        --inst.entity:SetCanSleep(false)
        inst.entity:Hide()
        inst.persists = false

        inst:AddTag("CLASSIFIED")

        inst:AddComponent("debuff")
        inst.components.debuff:SetAttachedFn(OnAttached)
        inst.components.debuff:SetDetachedFn(OnDetached)
        inst.components.debuff:SetExtendedFn(OnExtended)
        inst.components.debuff.keepondespawn = true

        if duration ~= nil then
            inst:AddComponent("timer")
            inst.components.timer:StartTimer("buffover", duration)
            inst:ListenForEvent("timerdone", OnTimerDone)
        end

        return inst
    end

    return Prefab("nutsbuff_" .. name, fn, nil, prefabs)
end

-- speed  20% 4min
-- speed2 50% 6min
-- speed3 10% 4min (currently only powder)

return MakeBuff("speed", speed_attach, nil, speed_detach, TUNING.NUTSBUFF_SPPED_DURATION, 1),
    MakeBuff("speed2", speed2_attach, nil, speed2_detach, TUNING.NUTSBUFF_SPPED2_DURATION, 1),
    MakeBuff("speed3", speed3_attach, nil, speed3_detach, TUNING.NUTSBUFF_SPPED3_DURATION, 1),
    MakeBuff("work", work_attach, nil, work_detach, TUNING.NUTSBUFF_WORK_DURATION),
    MakeBuff("strength", strength_attach, nil, strength_detach, TUNING.NUTSBUFF_STRENGTH_DURATION),
    MakeBuff("banana", banana_attach, nil, banana_detach, TUNING.NUTSBUFF_STRENGTH_DURATION),
    MakeBuff("moisture", moisture_attach, nil, moisture_detach, TUNING.NUTSBUFF_MOISTURE_DURATION),
    MakeBuff("sanity", sanity_attach, sanity_extend, nil, TUNING.NUTSBUFF_SANITY_DURATION),
    MakeBuff("powder", powder_attach), -- #HACK: Food
    MakeBuff("yutu", yutu_attach, nil, yutu_detach, TUNING.NUTSBUFF_SANITY_MOONCAKE_DURATION)
